package com.dm.cloud.auth.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.MD5;
import com.dm.cloud.auth.common.mode.AuthUserExtend;
import com.dm.cloud.auth.common.po.AuthRole;
import com.dm.cloud.auth.common.po.AuthUser;
import com.dm.cloud.auth.common.po.AuthUserRole;
import com.dm.cloud.auth.service.AuthPermissionService;
import com.dm.cloud.auth.service.AuthRoleService;
import com.dm.cloud.auth.service.AuthUserRoleService;
import com.dm.cloud.auth.util.Md5Util;
import com.dm.cloud.core.config.CommonConstants;
import com.dm.cloud.core.exception.CustomException;
import com.dm.cloud.core.mode.UserMode;
import com.dm.cloud.tkmybatis.service.BaseMapper;
import com.dm.cloud.auth.mapper.AuthUserMapper;
import com.dm.cloud.auth.service.AuthUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.util.Sqls;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;

/**
 * @author hcx
 * @type AuthUserServiceImpl.java
 * @desc AuthUser serviceImpl
 */
@Service

@Transactional

public class AuthUserServiceImpl implements AuthUserService {


    @Autowired
    private AuthUserMapper authUserMapper;

    @Autowired
    private AuthRoleService authRoleService;

    @Autowired
    private AuthPermissionService authPermissionService;

    @Autowired
    private AuthUserRoleService authUserRoleService;


    @Value("${sa-token.is-concurrent:true}")
    private String isConcurrent;

    @Override
    public BaseMapper getMapper() {
        return authUserMapper;
    }

    @Override
    public AuthUser findByUserName(String name) {
        return authUserMapper.findByUserName(name);
    }

    /**
     * 前置操作重写
     *
     * @param entity
     * @param operationEnum
     * @throws CustomException
     */
    @Override
    public void processBeforeOperation(AuthUser entity, BaseOperationEnum operationEnum) throws CustomException {
        if (operationEnum.equals(BaseOperationEnum.INSERT)) {

            //插入前将密码加密
            if (StrUtil.isNotEmpty(entity.getPassword())) {
                String pwd = entity.getPassword();
                Md5Util.EncryOption encry = Md5Util.encryptionByLevel(pwd, 3);
                entity.setPassword(encry.getEncryChart());
                entity.setSalt(String.join(",", encry.getSalts()));
            } else {
                throw new CustomException("密码不能为空");
            }
        } else if (operationEnum.equals(BaseOperationEnum.UPDATE)) {
            //修改前将密码加密
            if (StrUtil.isNotEmpty(entity.getPassword())) {
                AuthUser old = authUserMapper.selectByPrimaryKey(entity.getId());
                String salts = old.getSalt();
                String pwd = entity.getPassword();
                if (StrUtil.isNotEmpty(salts)) {
                    List<String> saltsArrs = Arrays.asList(salts.split(","));
                    Md5Util.EncryOption encry = Md5Util.encryptionBySalts(pwd, saltsArrs);
                    entity.setPassword(encry.getEncryChart());
                } else {
                    entity.setPassword(pwd);
                }
            }
        }

    }

    /**
     * 后置操作重写
     *
     * @param entity
     * @param operationEnum
     * @throws CustomException
     */
    @Override
    public void processAfterOperation(AuthUser entity, BaseOperationEnum operationEnum) throws CustomException {
        if (operationEnum.equals(BaseOperationEnum.SELECT)) {
            entity.setSalt(null);
            entity.setPassword(null);
        }else if (operationEnum.equals(BaseOperationEnum.DELETE)){
            //删除操作
            //删除关联角色
            authUserRoleService.delete(Example.builder(AuthUserRole.class)
                    .andWhere(Sqls.custom().andEqualTo("userId",entity.getId()))
                    .build());
            
        }
    }

    @Override
    public UserMode login(String name, String pwd, String role) {
        AuthUser user = findByUserName(name);
        // 登录处理函数
        if (user == null) {
            throw new CustomException("账号不存在", 401, null);
        }

        //加密处理
        if (StrUtil.isNotEmpty(user.getSalt())) {
            String[] saltArr = user.getSalt().split(",");
            MD5 md5 = MD5.create();
            for (String salt : saltArr) {
                if (StrUtil.isNotEmpty(salt)) {
                    pwd = md5.digestHex(pwd + salt, StandardCharsets.UTF_8);
                }
            }
        }

        if (user.getPassword().equals(pwd)) {
            List<String> userRoleIds = authRoleService.findRoleIdsByUid(user.getId());
            if (!userRoleIds.contains(role))
                throw new CustomException("当前用户与角色不匹配", 401, null);
            String loginId=null;
            if (StrUtil.isNotEmpty(isConcurrent) && isConcurrent.equals("true")) {
                loginId = user.getId() + "_" + IdUtil.fastUUID();
            }else{
                loginId = user.getId();
            }
            StpUtil.login(loginId);
            UserMode userMode = UserMode.builder()
                    .uid(user.getId())
                    .uname(user.getUserName())
                    .chineseName(user.getChineseName())
                    .build();
            List<String> currentRoles = Arrays.asList(role);
            userMode.setRoles(currentRoles);
//            UserPermission permissions = authPermissionService.findUserPermissionsByRoleIds(currentRoles);
//            userMode.setPermissions(permissions);
            StpUtil.getSessionByLoginId(loginId).set(CommonConstants.AUTH_USER_DETAIL, userMode);
            return userMode;
        }
        throw new CustomException("密码错误", 401, null);
    }

    @Override
    public AuthUserExtend inserExtend(AuthUserExtend authUserExtend) {
        String roleId=authUserExtend.getRoleId();
        if(StrUtil.isEmpty(roleId)){
            throw new CustomException("角色信息不能为空");
        }
        AuthUser authUser = BeanUtil.toBean(authUserExtend, AuthUser.class);
        insert(authUser); //插入

        String[] roleArr = roleId.split(",");
        for (String roleIdItem : roleArr) {
            AuthRole role = authRoleService.selectOne(roleIdItem);
            if(role==null){
                throw new CustomException("角色不存在");
            }
            authUserRoleService.insert(AuthUserRole.builder()
                    .roleId(roleIdItem)
                    .userId(authUser.getId())
                    .build());
        }
        authUserExtend = BeanUtil.toBean(authUser, AuthUserExtend.class);
        authUserExtend.setRoleId(roleId);
        return authUserExtend;
    }

    @Override
    public AuthUserExtend updateExtend(AuthUserExtend authUserExtend) {
        String roleId=authUserExtend.getRoleId();
        if(StrUtil.isEmpty(roleId)){
            throw new CustomException("角色信息不能为空");
        }
        AuthUser authUser = BeanUtil.toBean(authUserExtend, AuthUser.class);
        update(authUser); //修改
        //删除关联角色
        authUserRoleService.delete(Example.builder(AuthUserRole.class)
                .andWhere(Sqls.custom().andEqualTo("userId",authUserExtend.getId()))
                .build());
        //重新保存关联角色
        String[] roleArr = roleId.split(",");
        for (String roleIdItem : roleArr) {
            AuthRole role = authRoleService.selectOne(roleIdItem);
            if(role==null){
                throw new CustomException("角色不存在");
            }
            authUserRoleService.insert(AuthUserRole.builder()
                    .roleId(roleIdItem)
                    .userId(authUser.getId())
                    .build());
        }
        authUserExtend = BeanUtil.toBean(authUser, AuthUserExtend.class);
        authUserExtend.setRoleId(roleId);
        return authUserExtend;
    }

    @Override
    public List<AuthUser> findByAppCode(String appCode) {
        return authUserMapper.findByAppCode(appCode);
    }

}
